package com.droid.customcalendar.cal.view;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.droid.customcalendar.R;
import com.droid.customcalendar.cal.model.MonthCalendarDataGenerator;
import com.droid.customcalendar.cal.util.DateTimeUtils;
import com.droid.customcalendar.cal.view.MonthView.OnDateSelectedListener;

public class SimpleCalendarView extends RelativeLayout {

	private static final int INVALID_RES = 0;
	
	private MonthCalendarDataGenerator crtDataGenerator;
	private Locale locale;
	private Date minDate;
	private Button next;
	private Button prev;
	private TextView title;
	private MonthView monthView; 
	private DayOfWeekView weekView;
	private Animation prevAnim;
	private Animation nextAnim;
	private int nextBtnBackground;
	private int prevBtnBackground;
	private int dayOfWeekTextColor;
	private int dayOfWeekBackground;
	private int monthTitleSize;
	
	//TODO - try to find a faster way, a hash map or a sorted list
	private List<IntervalData> selectedDates; 
	
	public SimpleCalendarView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
		initAttr(context, attrs);
	}

	private void initAttr(Context context, AttributeSet attrs) {
		TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SimpleCalendarView, 0, 0);
		try {
			nextBtnBackground = array.getResourceId(R.styleable.SimpleCalendarView_nextBtnBackground, 0);
			prevBtnBackground = array.getResourceId(R.styleable.SimpleCalendarView_prevBtnBackground, 0);
			dayOfWeekBackground = array.getResourceId(R.styleable.SimpleCalendarView_dayOfWeekViewBackground, 0);
			dayOfWeekTextColor = array.getColor(R.styleable.SimpleCalendarView_dayOfWeekTextColor, 0);
			int defTitleSize = getResources().getDimensionPixelOffset(R.dimen.default_month_title_size);
			monthTitleSize = array.getDimensionPixelOffset(R.styleable.SimpleCalendarView_monthTitleSize, defTitleSize);
		} finally {
			array.recycle();
		}
		setTitleTextSize(monthTitleSize);
		setNextBtnBackground(nextBtnBackground);
		setPrevBtnBackground(prevBtnBackground);
		setDayOfWeekBackground(dayOfWeekBackground);
		setDayOfWeekTextColor(dayOfWeekTextColor);
	}
	
	private void init() {
		locale = Locale.getDefault();
		crtDataGenerator = createMonthDataGenerator(locale, null);
		View view = inflateRootView();
		next = (Button) view.findViewById(R.id.nextMonth);
		prev = (Button) view.findViewById(R.id.prevMonth);
		title = (TextView) view.findViewById(R.id.titleMonth);
		monthView = (MonthView) view.findViewById(R.id.monthView);
		weekView = (DayOfWeekView) view.findViewById(R.id.weekView);
		weekView.setDays(crtDataGenerator.getDays());
		setHeaderTitle();
		setButtonActions();
		setAnimation();
	}

	private void setAnimation() {
		Animation prev = AnimationUtils.loadAnimation(getContext(), R.anim.left_to_right_anim);
		Animation next = AnimationUtils.loadAnimation(getContext(), R.anim.right_to_left_anim);
		setChangeMonthAnimation(next, prev);
	}
	
	public void setChangeMonthAnimation(Animation next, Animation prev) {
		prevAnim = prev;
		nextAnim = next;
	}
	
	protected MonthCalendarDataGenerator createMonthDataGenerator(Locale locale, Date date) {
		return new MonthCalendarDataGenerator(date, locale);
	}
	
	protected View inflateRootView() {
		LayoutInflater inflater = LayoutInflater.from(getContext());
		return inflater.inflate(R.layout.simple_calendar_layout, this);
	}
	
	protected void setHeaderTitle() {
		title.setText(crtDataGenerator.getMonthName() + " " + crtDataGenerator.getYear());
	}

	protected void setButtonActions() {
		next.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				if (nextAnim != null) {
					monthView.startAnimation(nextAnim);
				}
				int nextMonth = crtDataGenerator.getCurrentMonth() + 1;
				changeMonth(nextMonth);
			}
		});
		prev.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				if (prevAnim != null) {
					monthView.startAnimation(prevAnim);
				}
				int prevMonth = crtDataGenerator.getCurrentMonth() - 1;
				changeMonth(prevMonth);
			}
		});
	}
	
	public void setOnDateSelected(OnDateSelectedListener dateSelectedListener) {
		monthView.setOnDateSelectedListener(dateSelectedListener);
	}

	public void setIntervalTextColor(Date startDate, Date endDate, int textColor) {
		updateInterval(startDate, endDate, INVALID_RES, textColor);
	}

	public void setIntervalBackground(Date startDate, Date endDate, int backResId) {
		updateInterval(startDate, endDate, backResId, INVALID_RES);
	}
	
	private void updateInterval(Date startDate, Date endDate, int backRes, int textColor) {
		if (selectedDates == null) {
			selectedDates = new ArrayList<IntervalData>();
		}
		IntervalData intervalData = new IntervalData(startDate, endDate, backRes, textColor);
		selectedDates.add(intervalData);
		updateSelectedDates(selectedDates);
	}

	private void updateSelectedDates(List<IntervalData> intervalDates) {
		for (IntervalData data: intervalDates) {
			if (data.backRes != INVALID_RES) {
				monthView.setIntervalBackgroundResource(data.startDate, data.endDate, data.backRes);
			} 
			if (data.textColor != INVALID_RES)  {
				monthView.setIntervalTextColor(data.startDate, data.endDate, data.textColor);
			}
		}
	}

	protected void changeMonth(int month) {
		Calendar calendar = Calendar.getInstance(locale);
		calendar.set(Calendar.MONTH, month);
		calendar.set(Calendar.YEAR, crtDataGenerator.getYear());
		crtDataGenerator = createMonthDataGenerator(locale, calendar.getTime());
		monthView.setMonthDataGenerator(crtDataGenerator);
		setHeaderTitle();
		if (selectedDates != null) {
			updateSelectedDates(selectedDates);
		}
		if (minDate != null && DateTimeUtils.isSameMonth(minDate, crtDataGenerator.getCurrentDate())) {
			prev.setVisibility(View.INVISIBLE);
		} else {
			prev.setVisibility(View.VISIBLE);
		}
	}
	
	public int getNextBtnBackground() {
		return nextBtnBackground;
	}

	public void setNextBtnBackground(int nextBtnBackground) {
		this.nextBtnBackground = nextBtnBackground;
		next.setBackgroundResource(nextBtnBackground);
	}

	public int getPrevBtnBackground() {
		return prevBtnBackground;
	}

	public void setPrevBtnBackground(int prevBtnBackground) {
		this.prevBtnBackground = prevBtnBackground;
		prev.setBackgroundResource(prevBtnBackground);
	}

	public int getDayOfWeekTextColor() {
		return dayOfWeekTextColor;
	}

	public void setDayOfWeekTextColor(int dayOfWeekTextColor) {
		this.dayOfWeekTextColor = dayOfWeekTextColor;
		weekView.setTextColor(dayOfWeekTextColor);
	}

	public int getDayOfWeekBackground() {
		return dayOfWeekBackground;
	}

	public void setDayOfWeekBackground(int dayOfWeekBackground) {
		this.dayOfWeekBackground = dayOfWeekBackground;
		weekView.setBackgroundResource(dayOfWeekBackground);
	}

	public void setTitleTextSize(int textSize) {
		title.setTextSize(textSize);
	}
	
	private void setCalendarMinDate(Date minDate) {
		if (DateTimeUtils.isSameMonth(minDate, crtDataGenerator.getCurrentDate())) {
			if (prev != null) {
				prev.setVisibility(View.INVISIBLE);
			}
		}
	}
	
	public void setMinDate(Date minDate) {
		this.minDate = minDate;
		monthView.setMinDate(minDate);
		setCalendarMinDate(minDate);
	}

	public Date getMinDate() {
		return minDate;
	}

	protected static class IntervalData {
		public Date startDate;
		public Date endDate;
		public int backRes;
		public int textColor;

		public IntervalData(Date start, Date end, int back, int color) {
			this.startDate = start;
			this.endDate = end;
			this.backRes = back;
			this.textColor = color;
		}
	}

}
